﻿using Microsoft.AspNetCore.Mvc.Filters;
using Newtonsoft.Json;
using RuoVea.ExFilter.Config;
using RuoVea.ExUtil;
using RuoVea.ExUtil.Exceptions;
using RuoVea.ExUtil.Time;
using System.Text;

namespace RuoVea.ExFilter;

/// <summary> 
/// 签名验证 ( appKey + signKey + timeStamp + data );
/// </summary>
public class SignFilter : IAsyncActionFilter, IOrderedFilter
{
    /// <summary>
    /// 排序
    /// </summary>
    public int Order => 8;

    /// <summary>
    /// 
    /// </summary>
    /// <param name="context"></param>
    /// <param name="next"></param>
    /// <returns></returns>
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        #region 安全签名认证
        var request = context.HttpContext.Request;
        var urlPath = request.Path.ToString().ToLower();
        var isSecurity = true;

        string[] IgnoreApi = ExFilterConfigs.FilterOptions.IgnoreApi;
        if (IgnoreApi != null)
        {
            foreach (var item in IgnoreApi.Where(item => urlPath.Contains(item)))
            {
                isSecurity = true;
            }
        }

        if (!isSecurity)
        {
            var method = request.Method;
            string appkey = string.Empty,
                timeStampsStr = string.Empty,
                signature = string.Empty;
            //客户的唯一标示
            long timestamp = 0;
            if (request.Headers.ContainsKey(ExFilterConfigs.FilterOptions.AppKeyName))
            {
                appkey = request.Headers[ExFilterConfigs.FilterOptions.AppKeyName].ToString();
                (ExFilterConfigs.FilterOptions.AppKeyName + "：" + appkey).WriteInfoLine();
            }

            //13位时间戳
            if (request.Headers.ContainsKey(ExFilterConfigs.FilterOptions.TimeStampName))
            {
                timeStampsStr = request.Headers[ExFilterConfigs.FilterOptions.TimeStampName];
                (ExFilterConfigs.FilterOptions.TimeStampName + "：" + timestamp).WriteInfoLine();
            }

            //签名
            if (request.Headers.ContainsKey(ExFilterConfigs.FilterOptions.SignatureName))
            {
                signature = request.Headers[ExFilterConfigs.FilterOptions.SignatureName];
                (ExFilterConfigs.FilterOptions.SignatureName + "：" + signature).WriteInfoLine();
            }

            if (string.IsNullOrEmpty(appkey) || string.IsNullOrEmpty(timeStampsStr) ||
                string.IsNullOrEmpty(signature))
            {
                ("ApiSecurity——请求不合法").WriteInfoLine();
                throw new ParamiterException("请求不合法");
            }

            if (!ExFilterConfigs.FilterOptions.AppKeys.Contains(appkey))
            {
                ("ApiSecurity——请求不合法-k").WriteInfoLine();
                throw new ParamiterException("请求不合法-k");
            }

            //判断timespan是否有效
            if (timeStampsStr == null) throw new ParamiterException("非法请求");

            timestamp = Convert.ToInt64(timeStampsStr);

            DateTime tonow = UnixTime.ToDateTime(timestamp);
            var expires_minute = tonow.Minute - DateTime.Now.Minute;
            bool falg = (expires_minute > ExFilterConfigs.FilterOptions.ExpiresMinute || expires_minute < -ExFilterConfigs.FilterOptions.ExpiresMinute);

            if (falg)
            {
                ("ApiSecurity——请求不合法-t").WriteInfoLine();
                throw new ParamiterException("请求不合法-t");
            }
            //根据请求类型拼接参数

            IDictionary<string, string> parameters = new Dictionary<string, string>();
            string data = string.Empty;
            switch (method)
            {
                case "POST":
                    context.HttpContext.Request.Body.Position = 0;
                    StreamReader stream = new StreamReader(context.HttpContext.Request.Body);
                    string body = await stream.ReadToEndAsync();
                    ("body：" + body).WriteInfoLine();
                    data = body;
                    context.HttpContext.Request.Body.Seek(0, SeekOrigin.Begin);
                    break;
                case "PUT":
                    context.HttpContext.Request.Body.Position = 0;
                    StreamReader streamPut = new StreamReader(context.HttpContext.Request.Body);
                    string bodyPut = await streamPut.ReadToEndAsync();
                    ("put：" + bodyPut).WriteInfoLine();
                    data = bodyPut;
                    context.HttpContext.Request.Body.Seek(0, SeekOrigin.Begin);
                    break;
                case "DELETE":
                    context.HttpContext.Request.Body.Position = 0;
                    StreamReader streamDel = new StreamReader(context.HttpContext.Request.Body);
                    string bodyDel = await streamDel.ReadToEndAsync();
                    ("put：" + bodyDel).WriteInfoLine();
                    data = bodyDel;
                    context.HttpContext.Request.Body.Seek(0, SeekOrigin.Begin);
                    break;
                case "GET":
                    {
                        var query = request.Query;
                        foreach (var item in query)
                        {
                            parameters.Add(item.Key, item.Value);
                        }

                        // 第二步：把字典按Key的字母顺序排序
                        IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters);
                        using IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator();

                        // 第三步：把所有参数名和参数值串在一起
                        StringBuilder stringBuilder = new StringBuilder();
                        while (dem.MoveNext())
                        {
                            string key = dem.Current.Key;
                            string value = dem.Current.Value;
                            if (!string.IsNullOrEmpty(key))
                            {
                                stringBuilder.Append(key).Append(value);
                            }
                        }

                        data = stringBuilder.ToString();
                        ("GET：" + JsonConvert.SerializeObject(data)).WriteInfoLine();
                        break;
                    }
            }

            if (!ApiSecurityValidate(timeStampsStr, appkey, data, signature))
            {
                ("ApiSecurity——参数不合法-Sign").WriteInfoLine();
                throw new ParamiterException("参数不合法");
            }
            //Console.WriteLine("success");
        }
        #endregion
    }

    /// <summary>
    /// 验证参数是否正确
    /// </summary>
    /// <param name="timeStamp"></param>
    /// <param name="appId"></param>
    /// <param name="data"></param>
    /// <param name="signature"></param>
    /// <returns></returns>
    private static bool ApiSecurityValidate(string timeStamp, string appId, string data, string signature)
    {
        //签名key
        var signKey = ExFilterConfigs.FilterOptions.SignKey;
        //拼接签名数据
        var signStr = appId + signKey + timeStamp + data;
        var newSign = ExCrypt.Md5Crypt.Encrypt(signStr);
        return newSign == signature;
    }
}
